我們前面介紹了 JSX 是如何渲染到頁面上的,那現在我們要來介紹元件的生命週期,在 React 中生命週期大概可以拆分成三個階段,包含:
1.裝載過程(Mount): 元件第一次在 DOM 渲染的過程
2.更新過程(Update): 元件重新被渲染的過程
3.卸載過程(Unmount): 元件從 DOM 上被刪除的過程
我們接下來會一一介紹,那在各版本當中有發生變動,我們也會特別提出來。
裝載過程依序調用的函數:
constructor -> static getDerivedStateFromProps ->
componentWillMount-> render -> componentDidMount
是元件初始化的地方也是元件接收由父元件傳遞過來 props 的地方,它只會被呼叫一次,這個地方也可以針對需要回調的函數預先進行 bind 的動作
getDerivedStateFromProps 是 React 16.3 提供的新方法,就類似之前的 componentWillReceiveProps()
當 props
發生變化的時候會被調用,若是父元件重新渲染,它也會被調用會返回新的 props
值
使用場景: 當元件內部的 state 變化依賴於 props,調用該函數
注意:如果這個操作(效果)是依賴於props的更動,最好改寫在 componentDidUpdate
裡
舉例而言:
src/multiCalculate.js
import React from 'react';
export default class MultiCalculate extends React.Component {
constructor() {
super();
this.state = {
currenctValue: 0,
}
}
static getDerivedStateFromProps(props, state) {
console.warn('取得 props 跟 state', props, state);
return {
currenctValue: props.data * 10
}
}
render() {
return (
<div>
<h1>當前 MultiCalculate 元件 currenctValue 值: {this.state.currenctValue}</h1>
</div>
)
}
}
src/App.js
import React from 'react';
import MultiCalculate from './multiCalculate';
export default class App extends React.Component {
constructor() {
super();
this.state = {
data: 0,
}
}
render() {
return (
<div>
<h1>當前 App 元件 data 值 {this.state.data}</h1>
<MultiCalculate data={this.state.data} />
<button onClick={() => {this.setState({data: this.state.data + 1})}}>
增加1
</button>
</div>
)
}
}
componentWillMount因為發生在元件渲染前,所以有許多人會在這裏初始化數據或是異步獲取數據,但如果是異步取得數據並不會等待數據返回後才進行渲染,React官方建議放在 constructor 去處理,所以 React16.3 後不推薦這方法。
render() 是作為渲染用,可以返回以下幾種類型:
componentDidMount 是元件已經在實體的 DOM 呈現之後才會呼叫的方法,所以如果是想要在元件產生後
先執行的動作都可以寫在 componentDidMount
。
使用場景: 通常會在這裏進行 數據請求(Ajax)
或是 加入事件監聽
當 props 或是 state 發生變化時就會引起元件的更新進而引起 render 的重新渲染
更新過程依序調用的函數:
componentWillReceiveProps(nextProps,nextState)-> static getDerivedStateFromProps()
->shouldComponentUpdate ->componentWillUpdate-> render -> getSnapshotBeforeUpdate()
->componentDidUpdate
componentWillReceiveProps 是在 props 更新時觸發,一般用於 props 參數更新時同步 state 參數,但如果componentWillReceiveProps 直接調用父元件某些有調用setState
的函數,會導致死循環,所以 React16.3 後不推薦這方法
同 Mount 敘述
shouldComponentUpdate通過返回 true
或 false
來決定是否觸發新的渲染,如果是 false
則不觸發後續的 componentWillUpdate -> render() 和 componentDidUpdate()。
在這裡,可以進行像是 this.props 跟 nextProps 或是 this.state 跟 nextState 的比較,只有在返回true時後續動作才會執行,以下為程式碼:
shouldComponentUpdate(nextProps, nextState) {
// this.props, this.state 代表原先的 props,state
// nextProps, nextState 代表後續的 props.state
if (nextProps.props.attribute !== this.props.attribute
|| nextState.state.attribute !== this.state.attribute) {
return true;
}
return false;
}
當接收到新的 props 或 state 時,在渲染前會執行該方法,一般是用於渲染前保存一些數據方便 render 後給值,但是因為 componentWillUpdate
與 componentDidUpdate
有時間差 (componentWillUpdate經過渲染、計算、更新DOM元素,最後才調用componentDidUpdate),在這過程可能因為用戶行為而導致 DOM 發生新的變化,而 componentWillUpdate 獲取的資料可能就不可靠了,所以 React16.3 後不推薦這方法
同 Mount 敘述
這個函數的作用是在 ComponentDidUpdate(真實DOM 更新前),進行快照然後將參數傳給ComponentDidUpdate,裡面的兩個參數 prevProps
、prevState
分別表示更新前的 props
和更新前的state
,這裏的返回值是一個snapshot
,這個函數都會伴隨著componentDidUpdate
一起使用。
這個方法是在更新完成後調用,而第三個參數 snapshot
來自於 getSnapShotBeforeUpdate(prevProps, prevState)的返回值。
可以使用 setState,會觸發 re-render
,所以要注意判斷避免死循環
卸載過程調用的函數:
componentWillUnmount()
是在元件卸載或銷毀前調用,這個方法主要用來做清理的工作,像是: